package main

import "fmt"

func assert(b bool, msg string) {
    if (!b) {
        panic(msg)
    }
}

func test1() {
    fmt.Println("run test1")

    // 使用 make 创建一个长度和容量都是 5 的切片
    slice := make([]string, 5)
    assert(len(slice) == 5, "len is not 5")
    assert(cap(slice) == 5, "cap is not 5")
    slice[4] = "400"

    // 使用 make 创建一个长度是 5 容量是 3 的切片
    slice2 := make([]int, 3, 5)
    assert(len(slice2) == 3, "len is not 3")
    assert(cap(slice2) == 5, "cap is not 5")
    slice2[2] = 200
    // slice2[3] = 300 // error

    // 使用切片字面量创建切片
    slice3 := []string {"Red", "Blue", "Green", "Yellow", "Pink"}
    assert(len(slice3) == 5, "len is not 5")
    assert(cap(slice3) == 5, "cap is not 5")
    slice3[4] = "Pink 2"

    // 使用切片字面量创建初始长度和容量的切片
    slice4 := []string {99:""}
    assert(len(slice4) == 100, "len is not 100")
    assert(cap(slice4) == 100, "cap is not 100")
    slice4[99] = "foo"

    // 使用字面量分别创建数组与切片
    arr := [3]int {10, 20, 30}
    slice5 := []int {10, 20, 30}
    assert(len(arr) == 3, "len is not 3")
    assert(len(slice5) == 3, "len is not 3")

    // nil 切片
    var slice6 []int
    // 空切片
    slice7 := make([]int, 0)
    slice8 := []int {}
    assert(len(slice6) == 0, "len is not 0")
    assert(cap(slice6) == 0, "cap is not 0")
    assert(len(slice7) == 0, "len is not 0")
    assert(cap(slice7) == 0, "cap is not 0")
    assert(len(slice8) == 0, "len is not 0")
    assert(cap(slice8) == 0, "cap is not 0")
    assert(slice6 == nil, "is not nil")
    assert(slice7 != nil, "is nil")
    assert(slice8 != nil, "is nil")

}

func test2() {
    fmt.Println("run test2")

    // 使用切片创建切片
    slice := []int {10, 20, 30, 40, 50}
    slice2 := slice[1:3]
    slice2[1] = 35
    assert(slice[2] == slice[2], "")
    assert(len(slice2) == 2, "")
    assert(cap(slice2) == 4, "")

    // slice2[2] = 45 // error
    slice3 := append(slice2, 45)
    assert(len(slice3) == 3, "")
    assert(cap(slice3) == 4, "")
    assert(slice3[2] == 45, "")
    assert(slice[3] == slice3[2], "")

    slice4 := append(slice3, 55)
    assert(len(slice4) == 4, "")
    assert(cap(slice4) == 4, "")
    assert(slice4[3] == 55, "")
    assert(slice[4] == slice4[3], "")

    // 新切换不再与 slice 共享底层数组
    slice5 := append(slice4, 60)
    assert(len(slice5) == 5, "")
    assert(slice5[4] == 60, "")
    assert(slice[4] == 55, "")
}

func test3() {
    fmt.Println("run test3")

    // 限制切片的容量
    slice := []int {10, 20, 30, 40, 50}
    slice2 := slice[2:3:3]
    assert(len(slice2) == 1, "")
    assert(cap(slice2) == 1, "")

    slice2[0] = 35
    assert(slice[2] == slice2[0], "")

    slice3 := append(slice2, 45) // 新的底层数组
    assert(len(slice3) == 2, "")
    assert(slice3[1] == 45, "")
    assert(slice[3] == 40, "")

    slice4 := append(slice3, 100, 200)
    assert(len(slice4) == 4, "")

    slice5 := []int {100, 200, 300}
    slice6 := append(slice, slice5...) // 将一个切片追加到另一个切片尾部
    assert(len(slice6) == 8, "")
    assert(slice6[7] == 300, "")
}

func test4() {
    fmt.Println("run test4")

    // 迭代切片
    slice := []int {10, 20, 30, 40, 50}

    var p *int
    var slice1 []int

    for i, v := range(slice) {
        if p == nil {
            p = &v
        } else {
            assert(p == &v, "")
        }
        assert(v == slice[i], "")
        slice1 = append(slice1, v)
    }

    for i := 0; i < len(slice); i += 1 {
        assert(slice[i] == slice1[i], "")
    }
}

func test5() {
    fmt.Println("run test5")

    // 多维切片
    slice := [][]int {{10}, {100, 200}}
    slice[0] = append(slice[0], 20)
}

func foo(slice []int) []int {
    slice[1e6 - 1] = 1000
    return slice
}

func test6() {
    fmt.Println("run test6")

    // 在函数间传递切片，参数共享底层数组
    slice := make([]int, 1e6)
    slice[1e6 - 1] = 999
    slice2 := foo(slice)

    assert(slice[1e6 - 1] == 1000, "")
    assert(slice2[1e6 - 1] == 1000, "")
}

func main() {
    test1()
    test2()
    test3()
    test4()
    test5()
    test6()
}
